#pragma once

#include "gut/pch.h"
#include "gut/Sampler.h"

namespace Gut
{
	struct Texture2DDesc
	{
		int target;
		int level = 0;
		int internalformat;
		int width;
		int height;
		int format;
		unsigned int dataType;
		void *data = 0;
	};
	struct Texture3DDesc
	{
		unsigned int target;
		int level;
		int internalformat;
		int width;
		int height;
		int depth;
		unsigned int format;
		unsigned int type;
		void *pixels;
	};

	struct TexSubImage3DDesc
	{
		unsigned int target;
		int level;
		int xoffset;
		int yoffset;
		int zoffset;
		int width;
		int height;
		int depth;
		unsigned int format;
		unsigned int type;
		void *pixels;
	};

	struct Texture
	{
		unsigned int ID = 0;
		virtual int Target() const = 0;
		void Bind()
		{
			glBindTexture(Target(), ID);
		}
		void TexSubImage3D(const TexSubImage3DDesc &desc)
		{
			Bind();
			glTexSubImage3D(desc.target, desc.level, desc.xoffset, desc.yoffset, desc.zoffset, desc.width, desc.height, desc.depth, desc.format, desc.type, desc.pixels);
		}
		void TexImage2D(const Texture2DDesc &desc)
		{
			Bind();
			glTexImage2D(desc.target, desc.level, desc.internalformat, desc.width, desc.height, 0, desc.format, desc.dataType, desc.data);
		}
		void TexImage3D(const Texture3DDesc &desc)
		{
			Bind();
			glTexImage3D(desc.target, desc.level, desc.internalformat, desc.width, desc.height, desc.depth, 0, desc.format, desc.type, desc.pixels);
		}
		void UnBind()
		{
			glBindTexture(Target(), 0);
		}
		void Active(unsigned int off) const
		{
			glActiveTexture(GL_TEXTURE0 + off);
			glBindTexture(Target(), ID);
		}
		void Create()
		{
			glGenTextures(1, &ID);
		}

		void SetSampler(const SamplerDesc &desc)
		{
			Bind();
			desc.BindTexture(Target());
		}
		void Delete()
		{
			glDeleteTextures(1, &ID);
		}

		void Mipmap()
		{
			glGenerateMipmap(Target());
		}
		virtual ~Texture()
		{
			Delete();
		}
	};

	struct Texture2D : public Texture
	{
		std::string m_Path;

		int Target() const
		{
			return GL_TEXTURE_2D;
		}
		bool CreateSTB(const std::string &path);
		// bool CreateHDR(const std::string& path);
	};

	struct TextureCube : public Texture
	{
		int Target() const
		{
			return GL_TEXTURE_CUBE_MAP;
		}
	};

	struct Texture2DArray : public Texture
	{
		int Target() const
		{
			return GL_TEXTURE_2D_ARRAY;
		}
	};
}